package com.flute.framework.data;

import java.io.File;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.amino.ds.lockfree.LockFreeList;
import org.apache.commons.io.FileUtils;

import com.flute.framework.FluteMonitor;
import com.flute.framework.StandardDate;
import com.flute.framework.data.constants.Constants;
import com.flute.framework.data.impl.CustomRawParser;
import com.flute.framework.data.impl.RawDataFileProvider;
import com.flute.framework.data.impl.XMLFileFilter;
import com.flute.framework.exception.IndexException;
import com.flute.framework.monitor.EventLogger;
import com.flute.framework.util.EventLoggerUtil;
import com.flute.framework.util.FileToolsUtil;
import com.flute.tools.data.DataIterator;
import com.flute.tools.data.DataRecord;
import com.flute.tools.data.file.FilesDataIterator;
import com.flute.tools.data.file.IFileHandler;
import com.flute.tools.util.ExceptionUtil;

/**
 * 基于文件系统的索引源数据。
 * 
 * 具体结构参照data目录。
 * 
 * 
 * 在此目录下所有的文件都是同种格式的，只是根据时间的不同，以及处理结果的
 * 
 * 不同分布在不同的目录下。new目录为新的未处理的数据，success目录为处理成功的数据,
 * 
 * fail目录为处理失败的数据。
 * 
 * 
 * 
 * @author Dave Yang
 * 
 */
public final class FileIndexData implements IIndexData, IFileHandler {
	private IRawdataParser<DataRecord, File> parser;
	private IRawDataProvider<File> dataProvider;
	private String location;
	private int day = 5;
	private List<File> filesToHistory = new LockFreeList<File>();
	private List<File> filesToDelete = new LockFreeList<File>();
	private List<File> filesToSucceed = new LockFreeList<File>();
	private List<File> filesToFailed = new LockFreeList<File>();

	public FileIndexData() {

	}

	public void moveFilesToPath(final List<File> files, final String path) {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		if (files == null) {
			return;
		}
		for (File file : files) {
			String fileName = file.getName();
			if (!FileToolsUtil.isValidXMLFile(fileName)) {
				EventLoggerUtil.info(fileName + "不是合法的日期XML文件", FluteMonitor
						.getImporterKey());
				continue;
			}

			try {
				String dateFileName = FileToolsUtil.getDateFileName(fileName);
				String dateFileDir = path + File.separator + dateFileName;
				File dateFile = new File(dateFileDir);

				EventLoggerUtil.info("移动" + file.getPath() + "文件到"
						+ dateFile.getPath(), FluteMonitor.getImporterKey());

				FileToolsUtil.moveFileToDir(file, dateFile);

				EventLoggerUtil.info("移动文件成功", FluteMonitor.getImporterKey());
			} catch (NumberFormatException e) {
				EventLoggerUtil.info(fileName + "不是合法的日期XML文件"
						+ ExceptionUtil.getExceptionContent(e), FluteMonitor
						.getImporterKey());
			} catch (IOException e) {
				EventLoggerUtil.error("移动文件" + fileName + "失败 "
						+ ExceptionUtil.getExceptionContent(e), FluteMonitor
						.getImporterKey());
			}
		}
	}

	public String getNewPath() {
		return getLocation() + File.separator + Constants.NEW;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(final String loc) {
		this.location = loc;
	}

	public IRawdataParser<DataRecord, File> getParser() {
		return parser;
	}

	public void setParser(final IRawdataParser<DataRecord, File> p) {
		this.parser = p;
	}

	public static void main(String[] args) {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		IRawDataProvider<File> provider = new RawDataFileProvider();
		IRawdataParser<DataRecord, File> parser = new CustomRawParser();
		FileIndexData indexData = new FileIndexData();
		indexData.setDataProvider(provider);
		indexData.setParser(parser);
		indexData.setDay(5);
		indexData.getAllDates();
		StandardDate date = new StandardDate(Long.parseLong("1280125018437"));
		indexData.getDataRecords(date);
		indexData.getCurrentDataRecords(Boolean.FALSE);
		indexData.roolbackTo(date);
	}

	/*
	 * @see com.flute.framework.data.IIndexData#getAllDates()
	 */
	@Override
	public List<StandardDate> getAllDates() {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		EventLoggerUtil.info("开始调用getAllDates方法......", FluteMonitor
				.getImporterKey());
		EventLoggerUtil.info("获取Succeed下面的文件", FluteMonitor.getImporterKey());
		File[] dateDirs = FileToolsUtil
				.getAllDateDirsUnderPath(getSucceedPath());
		EventLoggerUtil.info("获取Succeed下面的文件成功", FluteMonitor.getImporterKey());

		List<StandardDate> dateList = new ArrayList<StandardDate>();
		if (dateDirs == null || dateDirs.length == 0) {
			return dateList;
		}

		for (File dateDir : dateDirs) {
			String folderName = dateDir.getName();
			EventLoggerUtil.info("开始解析" + folderName, FluteMonitor
					.getImporterKey());
			EventLoggerUtil.info("转化" + folderName + "成日期", FluteMonitor
					.getImporterKey());
			StandardDate date = getStandardDate(folderName);
			addIfNotNull(dateList, date);
		}
		EventLoggerUtil.info("调用getAllDates方法结束......", FluteMonitor
				.getImporterKey());
		return dateList;
	}

	private void addIfNotNull(final List<StandardDate> dateList,
			final StandardDate date) {
		if (date != null) {
			dateList.add(date);
			EventLoggerUtil.info("转化成功的日期" + date.toString(), FluteMonitor
					.getImporterKey());
		}
	}

	private StandardDate getStandardDate(final String folderName) {
		StandardDate date = null;
		try {
			date = StandardDate.toDateByPattern(folderName,
					Constants.DATE_PATTERN);
		} catch (ParseException e) {
			EventLoggerUtil.info("文件" + folderName + "转化日期失败..."
					+ ExceptionUtil.getExceptionContent(e), FluteMonitor
					.getImporterKey());
			date = null;
		}
		return date;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.flute.framework.data.IIndexData#getCurrentDataRecords(boolean
	 * )
	 */
	@Override
	public DataIterator<DataRecord> getCurrentDataRecords(final boolean isUpdate) {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		// 每次调用时需要清空数据
		initSucceedList();
		initFailedList();

		EventLoggerUtil.info("开始调用getCurrentDataRecords方法......", FluteMonitor
				.getImporterKey());

		if (dataProvider == null || getLocation() == null || parser == null) {
			throw new InvalidParameterException(
					"The Provider, location and parser are not be null. Please check it and retry");
		}

		EventLoggerUtil.info("开始取原数据...", FluteMonitor.getImporterKey());
		List<File> rawDatas = dataProvider.getRawDatas();
		EventLoggerUtil.info("取原数据集成功...", FluteMonitor.getImporterKey());

		moveFilesToPath(rawDatas, getNewPath());

		if (isUpdate) {
			// 添加new文件下的文件
			EventLoggerUtil.info("更新操作开始......", FluteMonitor.getImporterKey());
			EventLoggerUtil.info("开始获取new下面文件", FluteMonitor.getImporterKey());

			List<File> files = FileToolsUtil.getAllFileUnderPath(getNewPath());

			EventLoggerUtil.info("获取new下面文件成功" + getNewPath(), FluteMonitor
					.getImporterKey());

			EventLoggerUtil.info("开始获取FilesDataIterator......", FluteMonitor
					.getImporterKey());
			FilesDataIterator<DataRecord> filesIterator = getIterator(files);
			EventLoggerUtil.info("获取FilesDataIterator成功......", FluteMonitor
					.getImporterKey());

			EventLoggerUtil.info("开始调用getCurrentDataRecords结束......",
					FluteMonitor.getImporterKey());

			return filesIterator;
		} else {
			// 添加New和Succeed下面的文件
			EventLoggerUtil.info("非更新操作开始......", FluteMonitor.getImporterKey());
			EventLoggerUtil.info("开始获取Succeed和New下面文件", FluteMonitor
					.getImporterKey());

			List<File> files = new ArrayList<File>();
			List<File> newFiles = FileToolsUtil
					.getAllFileUnderPath(getNewPath());
			List<File> succeedFiles = FileToolsUtil
					.getAllFileUnderPath(getSucceedPath());
			files.addAll(newFiles);
			files.addAll(succeedFiles);

			EventLoggerUtil.info("获取Succeed和New下面文件成功", FluteMonitor
					.getImporterKey());
			EventLoggerUtil.info("开始获取FilesDataIterator......", FluteMonitor
					.getImporterKey());
			FilesDataIterator<DataRecord> filesIterator = getIterator(files);
			EventLoggerUtil.info("获取FilesDataIterator成功......", FluteMonitor
					.getImporterKey());

			EventLoggerUtil.info("调用getCurrentDataRecords结束......", FluteMonitor
					.getImporterKey());
			return filesIterator;
		}
	}

	private void initFailedList() {
		if (filesToFailed == null) {
			filesToFailed = new LockFreeList<File>();
		} else {
			filesToFailed.clear();
		}
	}

	private void initSucceedList() {
		if (filesToSucceed == null) {
			filesToSucceed = new LockFreeList<File>();
		} else {
			filesToSucceed.clear();
		}
	}

	private FilesDataIterator<DataRecord> getIterator(final List<File> files) {
		File[] filesArray = new File[] {};
		filesArray = files.toArray(filesArray);
		FilesDataIterator<DataRecord> filesIterator = new FilesDataIterator<DataRecord>(
				filesArray);
		filesIterator.setParser(parser);
		filesIterator.setHandler(this);
		filesIterator.setFilter(new XMLFileFilter());
		return filesIterator;
	}

	public String getSucceedPath() {
		return getLocation() + File.separator + Constants.SUCCEED;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.flute.framework.data.IIndexData#getDataRecords(com.cpkf.
	 * yyjd.lily.framework.StandardDate)
	 */
	@Override
	public DataIterator<DataRecord> getDataRecords(final StandardDate date) {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		// 每次调用时需要清空数据
		initSucceedList();
		initFailedList();

		EventLoggerUtil.info("开始调用getDataRecords方法......", FluteMonitor
				.getImporterKey());
		if (date == null) {
			EventLoggerUtil.error("输入的日期参数不能为空", FluteMonitor.getImporterKey());
			throw new InvalidParameterException("输入的日期参数不能为空");
		}
		EventLoggerUtil
				.info("开始获取Succeed文件下面的文件", FluteMonitor.getImporterKey());
		List<File> files = FileToolsUtil.getAllFileBeforeStandardDate(
				getSucceedPath(), date);
		EventLoggerUtil
				.info("获取Succeed文件下面的文件成功", FluteMonitor.getImporterKey());
		EventLoggerUtil.info("开始获取FilesDataIterator", FluteMonitor
				.getImporterKey());
		FilesDataIterator<DataRecord> filesIterator = getIterator(files);
		EventLoggerUtil.info("获取FilesDataIterator成功", FluteMonitor
				.getImporterKey());

		EventLoggerUtil.info("调用getDataRecords结束......", FluteMonitor
				.getImporterKey());

		return filesIterator;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.flute.framework.data.IIndexData#roolbackTo(com.flute
	 * .framework.StandardDate)
	 */
	@Override
	public void roolbackTo(final StandardDate date) {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		// 每次调用时需要清空数据
		initDeleteList();

		EventLoggerUtil.info("开始调用roolbackTo方法......", FluteMonitor
				.getImporterKey());

		if (date == null) {
			EventLoggerUtil.error("输入的日期参数不能为空", FluteMonitor.getImporterKey());
			throw new InvalidParameterException("输入的日期参数不能为空");
		}

		EventLoggerUtil.info("开始获得Succeed下面的文件", FluteMonitor.getImporterKey());
		File[] dateDirs = FileToolsUtil
				.getAllDateDirsUnderPath(getSucceedPath());
		if (dateDirs == null || dateDirs.length == 0) {
			return;
		}
		EventLoggerUtil.info("获得Succeed下面的文件成功", FluteMonitor.getImporterKey());
		for (File dateDir : dateDirs) {
			if (dateDir.isDirectory() && !dateDir.isHidden()) {
				String dateString = dateDir.getName();
				StandardDate folderDate = getStandardDate(dateString);
				if (folderDate != null && folderDate.isAfter(date)) {
					filesToDelete.add(dateDir);
				}
			}
		}

		EventLoggerUtil.info("调用roolbackTo方法结束......", FluteMonitor
				.getImporterKey());
	}

	private void initDeleteList() {
		if (filesToDelete == null) {
			filesToDelete = new LockFreeList<File>();
		} else {
			filesToDelete.clear();
		}
	}

	@Override
	public void commit() throws IndexException {
		commitHistory();

		commitSucceed();

		commitFailed();

		commitDelete();

	}

	private void commitDelete() throws IndexException {
		if (filesToDelete != null) {
			for (File file : filesToDelete) {
				try {
					FileUtils.deleteDirectory(file);
				} catch (IOException e) {
					int times = 1;
					while (file.exists()) {
						try {
							times++;
							EventLoggerUtil.error("删除文件" + file.getName()
									+ "失败，将重新删除...... "
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							FileUtils.deleteDirectory(file);
						} catch (IOException e1) {
							EventLoggerUtil.error("重新删除文件" + file.getName()
									+ "失败，文件路径： " + file.getPath()
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							throwsIndexException(file, e1, times);
						}
					}
				}
			}
		}
	}

	private void commitFailed() throws IndexException {
		if (filesToFailed != null) {
			for (File file : filesToFailed) {
				try {
					moveFileToDir(file, Constants.FAILED);
				} catch (IOException e) {
					int times = 1;
					while (file.exists()) {
						try {
							times++;
							EventLoggerUtil.error("移动文件" + file.getName()
									+ "到failed文件夹失败，将尝试重新移动...... "
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							moveFileToDir(file, Constants.FAILED);
						} catch (IOException e1) {
							EventLoggerUtil.error("重移动文件" + file.getName()
									+ "失败，文件路径" + file.getPath()
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							throwsIndexException(file, e1, times);
						}
					}
				}
			}
		}
	}

	private void commitSucceed() throws IndexException {
		if (filesToSucceed != null) {
			for (File file : filesToSucceed) {
				try {
					moveFileToDir(file, Constants.SUCCEED);
				} catch (IOException e) {
					int times = 1;
					while (file.exists()) {
						try {
							times++;
							EventLoggerUtil.error("移动文件" + file.getName()
									+ "到succeed文件夹失败,将重新移动...... "
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							moveFileToDir(file, Constants.SUCCEED);
						} catch (IOException e1) {
							EventLoggerUtil.error("重移动文件" + file.getName()
									+ "失败，文件路径" + file.getPath()
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							throwsIndexException(file, e1, times);
						}
					}
				}
			}
		}
	}

	private void commitHistory() throws IndexException {
		File historyDir = new File(getHistoryPath());
		if (filesToHistory != null) {
			for (File dir : filesToHistory) {
				try {
					FileToolsUtil.moveSrcDirToDestDir(dir, historyDir);
				} catch (IOException e) {
					int times = 1;
					while (dir.exists()) {
						try {
							times++;
							EventLoggerUtil.error("移动文件" + dir.getName()
									+ "失败,将重新移动......"
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							FileToolsUtil.moveSrcDirToDestDir(dir, historyDir);
						} catch (IOException e1) {
							EventLoggerUtil.error("重移动文件" + dir.getName()
									+ "失败，文件路径" + dir.getPath()
									+ ExceptionUtil.getExceptionContent(e),
									FluteMonitor.getImporterKey());
							throwsIndexException(dir, e, times);
						}
					}
				}
			}
		}
	}

	private void throwsIndexException(File file, IOException e, int times)
			throws IndexException {
		if (times >= 5) {
			throw new IndexException("重移" + file.getName() + "文件失败，文件路径"
					+ file.getPath() + ExceptionUtil.getExceptionContent(e));
		}
	}

	@Override
	public void openTransaction() {
	}

	public IRawDataProvider<File> getDataProvider() {
		return dataProvider;
	}

	public void setDataProvider(final IRawDataProvider<File> provider) {
		this.dataProvider = provider;
	}

	public int getDay() {
		return day;
	}

	public void setDay(int d) {
		this.day = d;
	}

	@Override
	public void failFile(final File file) {
		failFile(file, null);
	}

	@Override
	public void failFile(final File file, final Exception e) {
		if (e != null) {
			EventLoggerUtil.info("解析" + file.getName() + "失败..."
					+ ExceptionUtil.getExceptionContent(e), FluteMonitor
					.getImporterKey());
		} else {
			EventLoggerUtil.info("解析" + file.getName() + "失败...", FluteMonitor
					.getImporterKey());
		}
		EventLoggerUtil.info("失败文件的路径是：" + file.getPath(), FluteMonitor
				.getImporterKey());

		try {
			EventLoggerUtil.info("文件的内容："
					+ FileUtils.readFileToString(file, Constants.UTF8_CHARSET),
					FluteMonitor.getImporterKey());
		} catch (IOException e1) {
			EventLoggerUtil.error("取文件" + file.getName() + "内容失败："
					+ ExceptionUtil.getExceptionContent(e1), FluteMonitor
					.getImporterKey());
		}

		EventLoggerUtil.info("添加" + file.getName() + "到FAILED LIST下",
				FluteMonitor.getImporterKey());

		filesToFailed.add(file);

		EventLoggerUtil.info("添加" + file.getName() + "成功", FluteMonitor
				.getImporterKey());
	}

	@Override
	public void successFile(final File file) {
		EventLoggerUtil.info("解析" + file.getName() + "成功...", FluteMonitor
				.getImporterKey());
		EventLoggerUtil.info("开始添加" + file.getName() + "到SUCCEED List下",
				FluteMonitor.getImporterKey());
		filesToSucceed.add(file);
		EventLoggerUtil.info("添加" + file.getName() + "成功", FluteMonitor
				.getImporterKey());
	}

	public void moveFileToDir(final File file, final String dirName)
			throws IOException {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		EventLoggerUtil.info("开始移动文件" + file.getName() + "到" + location
				+ File.separator + dirName, FluteMonitor.getImporterKey());
		File dateDir = FileToolsUtil.getDateDir(file.getName(), location
				+ File.separator + dirName);
		File destFile = new File(dateDir.getPath() + File.separator
				+ file.getName());
		if (!destFile.exists()) {
			FileToolsUtil.moveFileToDir(file, dateDir);
		}
		EventLoggerUtil.info("移动文件" + file.getName() + "成功", FluteMonitor
				.getImporterKey());
	}

	private String getHistoryPath() {
		return location + File.separator + Constants.HISTORY;
	}

	public void backupFile() {
		EventLogger.startNewEvent(FluteMonitor.getImporterKey());
		// 每次调用时需要清空数据
		initHistoryList();

		EventLoggerUtil.info("开始备份文件......", FluteMonitor.getImporterKey());
		File[] dateDirs = FileToolsUtil
				.getAllDateDirsUnderPath(getSucceedPath());

		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE, -day);
		StandardDate dateBeforeDay = new StandardDate(calendar.getTime());

		for (File dateDir : dateDirs) {
			try {
				StandardDate date = StandardDate.toDateByPattern(dateDir
						.getName(), Constants.DATE_PATTERN);
				if (date.isBefore(dateBeforeDay)) {
					EventLoggerUtil.info("添加" + dateDir + "到history list",
							FluteMonitor.getImporterKey());
					filesToHistory.add(dateDir);
				}
			} catch (ParseException e) {
				e.printStackTrace();
				EventLoggerUtil.error("移动文件失败"
						+ ExceptionUtil.getExceptionContent(e), FluteMonitor
						.getImporterKey());
			}
		}

		EventLoggerUtil.info("备份文件成功......", FluteMonitor.getImporterKey());
	}

	private void initHistoryList() {
		if (filesToHistory == null) {
			filesToHistory = new LockFreeList<File>();
		} else {
			filesToHistory.clear();
		}
	}

	@Override
	public void processData(final DataRecord data) {
		// TODO Auto-generated method stub

	}

	@Override
	public DataRecord getLatestDataRecordByKey(String key) {
		// TODO Auto-generated method stub
		return null;
	}
}
